package com.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.system.constant.CommonConstant;
import com.system.constant.HTTPStatus;
import com.system.entity.Menu;
import com.system.entity.Permission;
import com.system.entity.Role;
import com.system.entity.TeacherRole;
import com.system.mapper.RoleMapper;
import com.system.mapper.TeacherRoleMapper;
import com.system.response.Result;
import com.system.response.role.RoleDtoResponse;
import com.system.service.MenuService;
import com.system.service.PermissionService;
import com.system.service.RoleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.system.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 角色表 服务实现类
 * </p>
 *
 * @author zfc
 * @since 2023-04-20
 */
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private PermissionService permissionService;//权限

    @Autowired
    private MenuService menuService;//菜单

    @Override
    public Set<String> selectAllRoleNamesByUsername(String username) {
        return roleMapper.selectAllRoleNamesByUsername(username);
    }

    @Override
    public boolean addRole(Role role) {
        //角色新增
        int insert = roleMapper.insert(role);
        if (insert > 0) {
            //1.1、权限列表不为空
            if (role.getPermission() != null) {
                //1.2、权限id
                Integer[] permissionIds = new Integer[role.getPermission().size()];
                for (int i = 0; i < role.getPermission().size(); i++) {
                    permissionIds[i] = role.getPermission().get(i).getId();
                }
                //1.2、批量绑定权限
                permissionService.roleBoundPermission(role.getId(), permissionIds);
            }
            //2.1 菜单列表不为空
            if (role.getMenu() != null) {
                //2.2 菜单id
                Integer[] menuIds = new Integer[role.getMenu().size()];
                for (int i = 0; i < role.getMenu().size(); i++) {
                    menuIds[i] = role.getMenu().get(i).getId();
                }
                //2.3 批量绑定菜单
                menuService.roleBoundMenu(role.getId(), menuIds);
            }
            return true;
        }
        return false;
    }

    @Override
    public boolean completelyDeleteRoleById(Integer id) {
        return roleMapper.deleteById(id) > 0;
    }

    @Override
    public boolean updateRole(Role role) {
        boolean b = roleMapper.updateById(role) > 0;
        if (b) {

            //1.1 查看当前角色权限是否为空
            if (role.getPermission() != null) {
                //1.2 删除该角色所有权限
                permissionService.deleteRoleBoundPermissionById(role.getId());
                //1.3、权限id
                Integer[] permissionIds = new Integer[role.getPermission().size()];
                for (int i = 0; i < role.getPermission().size(); i++) {
                    permissionIds[i] = role.getPermission().get(i).getId();
                }
                //1.4 重新插入权限
                permissionService.roleBoundPermission(role.getId(), permissionIds);
            }

            //2.1 菜单列表不为空
            if (role.getMenu() != null) {
                //2.2 删除该角色的所有菜单
                menuService.deleteRoleBoundMenusById(role.getId());
                //2.3 菜单id
                Integer[] menuIds = new Integer[role.getMenu().size()];
                for (int i = 0; i < role.getMenu().size(); i++) {
                    menuIds[i] = role.getMenu().get(i).getId();
                    //查看是否有父菜单，如果有则直接添加父菜单
                    addParentMenu(role.getId(), role.getMenu().get(i).getId());
                }
                //2.4 批量绑定菜单
                menuService.roleBoundMenu(role.getId(), menuIds);
            }
        }
        return b;
    }

    /**
     * 因为前端传过来的值不包括父菜单，所以这里遍历所有子菜单，如果这个子菜单存在父菜单就需要新增绑定父菜单，并且绑定的父菜单不能重复
     * 为角色绑定父菜单
     *
     * @param roleId 角色id
     * @param menuId 菜单id
     */
    public void addParentMenu(Integer roleId, Integer menuId) {

        //1、通过菜单id查询相关信息
        Menu menu = menuService.selectMenuById(menuId);
        //如果父id不等于0，代表该菜单绑定了父菜单
        if (menu.getParentId() != 0) {
            //2、如果存在父菜单则需要判断该父菜单是否存在，不存在则添加
            Integer[] arrParentMenuId = {menu.getParentId()};
            //检查该角色是否重复绑定菜单 true:代表空
            boolean flg = menuService.checkRoleBoundMenuUnique(roleId, arrParentMenuId);
            if (flg) {
                menuService.roleBoundMenu(roleId, arrParentMenuId);
            }
            //1.2、如果存在父菜单还需要判断该父菜单是否也存在父菜单，一直遍历
            addParentMenu(roleId, menu.getParentId());
        }
    }

    @Override
    public PageInfo<Role> roleLimit(RoleDtoResponse roleResponse) {
        if (roleResponse.getPageSize()==null || roleResponse.getPageSize()<0) roleResponse.setPageSize(1);
        if (roleResponse.getPageNum()==null || roleResponse.getPageNum()<10) roleResponse.setPageNum(10);

        PageHelper.startPage(roleResponse.getPageSize(), roleResponse.getPageNum());
        List<Role> roleList = roleMapper.selectList(
                new LambdaQueryWrapper<Role>()
                        .eq(!StringUtils.isNull(roleResponse.getDelete()), Role::getIsDelete,roleResponse.getDelete())
                        .like(!StringUtils.isNull(roleResponse.getName()), Role::getRoleName, roleResponse.getName())
                        .orderByAsc(Role::getCreateDate)
        );
        Integer count = roleMapper.selectCount(new LambdaQueryWrapper<Role>()
                .eq(!StringUtils.isNull(roleResponse.getDelete()), Role::getIsDelete,roleResponse.getDelete())
                .like(!StringUtils.isNull(roleResponse.getName()), Role::getRoleName, roleResponse.getName())
                .orderByAsc(Role::getCreateDate));
        PageInfo<Role> info = new PageInfo<>(roleList);
        info.setSize(count);

        //角色查询出来后需要，把角色关联的权限、菜单也查询出来
        for (int i = 0; i < info.getList().size(); i++) {
            Integer roleId = info.getList().get(i).getId();
            //通过角色id查询绑定的权限
            List<Permission> permissionList = permissionService.queryRolesBoundPermission(roleId);

            //通过角色id查询绑定的菜单
            List<Menu> menuList = menuService.queryRolesBoundMenus(roleId);

            info.getList().get(i).setPermission(permissionList);
            info.getList().get(i).setMenu(menuList);
        }
        return info;
    }

    @Override
    public Role selectRoleById(Integer id) {

        return roleMapper.selectById(id);
    }

    @Override
    public List<Role> selectAllRole() {
        return roleMapper.selectList(
                new LambdaQueryWrapper<Role>()
                        .eq(Role::getIsDelete, CommonConstant.STATUS_NORMAL)
        );
    }

    @Override
    public boolean checkRoleUnique(Role role) {
        Role newRole = new Role();
        newRole.setRoleName(role.getRoleName());
        newRole.setId(role.getId());

        if (!StringUtils.isNull(newRole.getRoleName())) {
            newRole.setId(null);
        }

        Role selectOne = roleMapper.selectOne(
                new LambdaQueryWrapper<Role>()
                        .eq(!StringUtils.isNull(newRole.getRoleName()), Role::getRoleName, newRole.getRoleName())
                        .eq(!StringUtils.isNull(newRole.getId()), Role::getId, newRole.getId())
                        .eq(Role::getIsDelete, CommonConstant.STATUS_NORMAL)
        );
        return !StringUtils.isNull(selectOne);
    }

    @Override
    public boolean checkRoleNameIsOneself(Role role) {
        Role role1 = roleMapper.selectById(role.getId());
        if (!role.getRoleName().equals(role1.getRoleName())) {
            return true;
        }
        return false;
    }

    @Autowired
    private TeacherRoleMapper teacherRoleMapper;

    @Override
    public Set<Role> queryTeacherBoundRoles(Integer teacherId) {

        //通过角色id查询角色绑定的角色id
        List<TeacherRole> roleIdList = teacherRoleMapper.selectList(
                new LambdaQueryWrapper<TeacherRole>()
                        .eq(TeacherRole::getTeacherId, teacherId).select(TeacherRole::getRoleId)
        );
        if (roleIdList.size()==0) return new HashSet<>();
        //将绑定的角色id存入数组
        Integer[] roleIds = new Integer[roleIdList.size()];
        for (int i = 0; i < roleIdList.size(); i++) {
            roleIds[i] = roleIdList.get(i).getRoleId();
        }
        //通过数组查询绑定的角色数据
        List<Role> roleList = roleMapper.selectList(
                new LambdaQueryWrapper<Role>()
                        .in(Role::getId, roleIds)
        );

        return roleList.stream().collect(Collectors.toSet());

    }

    @Transactional(rollbackFor = Exception.class, timeout = 1000 * 60)
    @Override
    public Result teacherBoundRoles(Integer teacherId, Integer[] roleIds) {

        //1、通过用户id删除该用户绑定的所有角色
        teacherRoleMapper.delete(new LambdaQueryWrapper<TeacherRole>().eq(TeacherRole::getTeacherId, teacherId));

        if (roleIds.length == 0) {
            return new Result().setCode(HTTPStatus.SUCCESS).setMessage("操作成功！");
        }

        for (Integer roleId : roleIds) {
            TeacherRole tr = new TeacherRole();
            tr.setTeacherId(teacherId);
            tr.setRoleId(roleId);
            int insert = teacherRoleMapper.insert(tr);
            if (insert < 1) {
                return new Result().setCode(HTTPStatus.BAD_REQUEST).setMessage("执行错误，请联系管理员！");
            }
        }
        return new Result().setCode(HTTPStatus.SUCCESS).setMessage("操作成功！");
    }

    @Override
    public boolean checkTeacherBoundRoles(TeacherRole tr) {
        List<TeacherRole> teacherRoles = teacherRoleMapper.selectList(
                new LambdaQueryWrapper<TeacherRole>()
                        .eq(!StringUtils.isNull(tr.getRoleId()), TeacherRole::getRoleId, tr.getRoleId())
                        .eq(!StringUtils.isNull(tr.getTeacherId()), TeacherRole::getTeacherId, tr.getTeacherId())
        );
        return teacherRoles.size() > 0;
    }

}